#include <libdswutility/dswptzctrl.h>

#define PTZ_STOP 0x0000
#define PTZ_UP 0x0008
#define PTZ_DOWN 0x0010
#define PTZ_LEFT 0x0004
#define PTZ_RIGHT 0x0002
#define PTZ_ZOOMIN 0x0020
#define PTZ_ZOOMOUT 0x0040
#define PTZ_FOCUSIN 0x0080
#define PTZ_FOCUSOUT 0x0100
#define PTZ_APERTUREIN 0x0200
#define PTZ_APERTUREOUT 0x0400
#define PTZ_LIGHTOFF 0x000b
#define PTZ_LIGHTON 0x0009
#define PTZ_PTGOTO 0x0007
#define PTZ_PTSET 0x0003
#define PTZ_PTDEL 0x0005

#define PTZ_SPEED_LOW 0x00
#define PTZ_SPEED_MID 0x01
#define PTZ_SPEED_HIGH 0x02

#define PTZ_PT_LAST 0x20

#define PTZ_SEND_CHECK (100 * 1000)
#define MAX_PTZ_CMD_SIZE 32

CDswPTZCtrl::CDswPTZCtrl(LPST_ENV_T pEnv, LPST_CONSOLE_INFO_T pInfo)
: CDswconsole_base(pEnv, CON_SESSION_PTZ, pInfo)
{
	int i;
	LOG4CPLUS_DEBUG(log_dsw, "Create CDswPTZCtrl class!");
	pthread_mutex_init(&m_nLock, NULL);
	for (i = 0; i < MAX_PTZ_CMD_SIZE; i++){
		LPST_PTZ_CMD_T pNode = new ST_PTZ_CMD_T;
		m_nEmptyList.push_back(pNode);
	}
	for (i = 0; i < MAX_CHANNEL_LOCAL; i++){
		m_nGobackTask[i].nTask.ev = NULL;
		m_nGobackTask[i].pCaller = this;
	}
	CREATE_EV(m_nPtzTask, 0, PTZ_SEND_CHECK, pEnv->pEvBase, CDswPTZCtrl::cbPtzSendTask, this);
}

CDswPTZCtrl::~CDswPTZCtrl()
{
	int i;
	for (i = 0; i < MAX_CHANNEL_LOCAL; i++){
		CLEAR_EV(m_nGobackTask[i].nTask);
	}
	CLEAR_EV(m_nPtzTask);
	while(!m_nEmptyList.empty()){
		LPST_PTZ_CMD_T pNode = m_nEmptyList.front();
		m_nEmptyList.pop_front();
		delete pNode;
	}
	while(!m_nPtzCmdList.empty()){
		LPST_PTZ_CMD_T pNode = m_nPtzCmdList.front();
		m_nEmptyList.pop_front();
		delete pNode;
	}
	pthread_mutex_destroy(&m_nLock);
	LOG4CPLUS_DEBUG(log_dsw, "Destroy CDswPTZCtrl class!");
}

void CDswPTZCtrl::PtzGobackTask(int fd, short events, LPST_PTZ_CMD_T pCmd)
{
	PutPTZCmd2Task(pCmd->nPTZCmd, pCmd->nDelayMs);
}

void CDswPTZCtrl::PtzSendTask(int fd, short events)
{
	MUTEX_LOCK(&m_nLock);
	if (!m_nPtzCmdList.empty()){
		LPST_PTZ_CMD_T pCmd = m_nPtzCmdList.front();
		m_nPtzCmdList.pop_front();
/*		printf("ptz data = ");
		for (int i = 0; i < pCmd->nLen; i++)
			printf("%02x, ", pCmd->nPTZCmd[i]);
		printf("\n");*/
		if (pCmd->nDelayMs <= 0){
			evbuffer_add(bufferevent_get_output(m_pBev), pCmd->nPTZCmd, pCmd->nLen);
			m_nEmptyList.push_back(pCmd);
		}
		else{
			pCmd->nDelayMs -= (PTZ_SEND_CHECK / 1000);
			m_nPtzCmdList.push_back(pCmd);
		}
	}
	MUTEX_UNLOCK(&m_nLock);
	TRIG_EV(m_nPtzTask, 0, PTZ_SEND_CHECK);
}

void CDswPTZCtrl::SetPTZAction(LPST_APP_PTZ_T pAppPtzAction)
{
	char sCmd[16] = {0};
	int nDelayms = 0;
	if (!pAppPtzAction->nPTZCmd.bLocal)
		return;
	sCmd[0] = 0xff;
	sCmd[1] = (pAppPtzAction->nPTZCmd.nAddr & 0xff);
	switch(pAppPtzAction->nPTZCmd.nCmdId){
	case CMD_PTZ_SETCURPOS:
		sCmd[2] = (PTZ_PTSET >> 8);
		sCmd[3] = (PTZ_PTSET & 0xff);
		sCmd[4] = (pAppPtzAction->nPTZCmd.nCmdData.nCurPos.posid >> 8);
		sCmd[5] = (pAppPtzAction->nPTZCmd.nCmdData.nCurPos.posid & 0xff);
		break;
	case CMD_PTZ_GOTO:
		sCmd[2] = (PTZ_PTGOTO >> 8);
		sCmd[3] = (PTZ_PTGOTO & 0xff);
		sCmd[4] = (pAppPtzAction->nPTZCmd.nCmdData.nGoto.posid >> 8);
		sCmd[5] = (pAppPtzAction->nPTZCmd.nCmdData.nGoto.posid & 0xff);
		break;
	case CMD_PTZ_MOVE:
		if (pAppPtzAction->nPTZCmd.nCmdData.nMove.fx & MASK_UP){
			sCmd[2] = (PTZ_UP >> 8);
			sCmd[3] = (PTZ_UP & 0xff);
		}
		else if (pAppPtzAction->nPTZCmd.nCmdData.nMove.fx & MASK_DOWN){
			sCmd[2] = (PTZ_DOWN >> 8);
			sCmd[3] = (PTZ_DOWN & 0xff);
		}
		else if (pAppPtzAction->nPTZCmd.nCmdData.nMove.fx & MASK_LEFT){
			sCmd[2] = (PTZ_LEFT >> 8);
			sCmd[3] = (PTZ_LEFT & 0xff);
		}
		else if (pAppPtzAction->nPTZCmd.nCmdData.nMove.fx & MASK_RIGHT){
			sCmd[2] = (PTZ_RIGHT >> 8);
			sCmd[3] = (PTZ_RIGHT & 0xff);
		}
		else
			return;
		if (pAppPtzAction->nPTZCmd.nCmdData.nMove.speed == PTZ_SPEED_H){
			sCmd[4] = (PTZ_SPEED_HIGH >> 8);
			sCmd[5] = (PTZ_SPEED_HIGH & 0xff);
		}
		else if (pAppPtzAction->nPTZCmd.nCmdData.nMove.speed == PTZ_SPEED_M){
			sCmd[4] = (PTZ_SPEED_MID >> 8);
			sCmd[5] = (PTZ_SPEED_MID & 0xff);
		}
		else{
			sCmd[4] = (PTZ_SPEED_LOW >> 8);
			sCmd[5] = (PTZ_SPEED_LOW & 0xff);
		}
		nDelayms = pAppPtzAction->nPTZCmd.nCmdData.nMove.dur;
		break;
	case CMD_PTZ_STOP:
		sCmd[2] = (PTZ_STOP >> 8);
		sCmd[3] = (PTZ_STOP & 0xff);
		sCmd[4] = 0x00;
		sCmd[5] = 0x00;
		break;
	default:
		return;
		break;
	}
	sCmd[6] = (sCmd[1] + sCmd[2] + sCmd[3] + sCmd[4] + sCmd[5]) % 0x100;
	PutPTZCmd2Task(sCmd, 0);
	if ((pAppPtzAction->nPTZCmd.nCmdId == CMD_PTZ_MOVE) && (nDelayms > 0)){
		sCmd[2] = (PTZ_STOP >> 8);
		sCmd[3] = (PTZ_STOP & 0xff);
		sCmd[4] = 0x00;
		sCmd[5] = 0x00;
		sCmd[6] = (sCmd[1] + sCmd[2] + sCmd[3] + sCmd[4] + sCmd[5]) % 0x100;
		PutPTZCmd2Task(sCmd, nDelayms);
	}
	if (pAppPtzAction->bNeedGoback){
		sCmd[0] = 0xff;
		sCmd[1] = (pAppPtzAction->nPTZCmd.nAddr & 0xff);
		sCmd[2] = (PTZ_PTGOTO >> 8);
		sCmd[3] = (PTZ_PTGOTO & 0xff);
		sCmd[4] = (defLastPTZSet >> 8);
		sCmd[5] = (defLastPTZSet & 0xff);
		sCmd[6] = (sCmd[1] + sCmd[2] + sCmd[3] + sCmd[4] + sCmd[5]) % 0x100;
		memcpy(m_nGobackTask[pAppPtzAction->nCh].nPtzCmd.nPTZCmd, sCmd, 7);
		m_nGobackTask[pAppPtzAction->nCh].nPtzCmd.nLen = 7;
		m_nGobackTask[pAppPtzAction->nCh].nPtzCmd.nDelayMs = 0;
		if (m_nGobackTask[pAppPtzAction->nCh].nTask.ev){
			TRIG_EV(m_nGobackTask[pAppPtzAction->nCh].nTask, pAppPtzAction->nGobackSec, 0);
		}
		else{
			CREATE_EV(m_nGobackTask[pAppPtzAction->nCh].nTask, pAppPtzAction->nGobackSec, 0, m_pEnv->pEvBase, CDswPTZCtrl::cbPtzGobackTask, &m_nGobackTask[pAppPtzAction->nCh]);
		}
	}
}

void CDswPTZCtrl::PutPTZCmd2Task(char* pCmd, int nDelayms)
{
	MUTEX_LOCK(&m_nLock);
	LPST_PTZ_CMD_T pNode = NULL;
	if (m_nEmptyList.empty()){
		pNode = m_nPtzCmdList.front();
		m_nPtzCmdList.pop_front();
	}
	else{
		pNode = m_nEmptyList.front();
		m_nEmptyList.pop_front();
	}
	memcpy(pNode->nPTZCmd, pCmd, 7);
	pNode->nLen = 7;
	pNode->nDelayMs = nDelayms;
	m_nPtzCmdList.push_back(pNode);
	MUTEX_UNLOCK(&m_nLock);
}

int CDswPTZCtrl::OnMessage(EN_MSG_TYPE nMsgType, void * pParam)
{
	switch(nMsgType){
	case PMSG_SET_PTZACTION:
		SetPTZAction((LPST_APP_PTZ_T)pParam);
		break;
	}
	return 0;
}

